package com.linq.cool.common.datascope.aspect;


import com.linq.cool.api.domain.SysRole;
import com.linq.cool.api.vo.LoginUser;
import com.linq.cool.api.vo.SysUserVO;
import com.linq.cool.common.constants.Constants;
import com.linq.cool.common.constants.UserConstants;
import com.linq.cool.common.core.domain.BaseDTO;
import com.linq.cool.common.core.utils.StringUtils;
import com.linq.cool.common.datascope.annotation.DataScope;
import com.linq.cool.common.security.service.SysTokenService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @Author: yqlin
 * @Date: 2020/12/29 20:21
 * @Description: 数据过滤处理
 * @Version: 1.0.0
 */
@Aspect
@Component
@Slf4j
public class DataScopeAspect {
    @Autowired
    private SysTokenService tokenService;

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.linq.cool.common.datascope.annotation.DataScope)")
    public void dataScopePointCut() {
    }

    @Before("dataScopePointCut()")
    public void before(JoinPoint joinPoint) {
        handleDataScope(joinPoint);
    }

    protected void handleDataScope(final JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        DataScope dataScopeAnnotation = method.getAnnotation(DataScope.class);
        if (dataScopeAnnotation != null) {
            // 获取当前登录用户
            LoginUser loginUser = tokenService.getLoginUser();
            if (StringUtils.isNotNull(loginUser)) {
                SysUserVO currentUser = loginUser.getSysUserVO();
                // 如果是超级管理员,则不过滤数据
                if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
                    dataScopeFilter(joinPoint, currentUser, dataScopeAnnotation.deptAlias(), dataScopeAnnotation.userAlias());
                }
            }
        }
    }

    /**
     * 数据权限过滤
     *
     * @param joinPoint 切点
     * @param user      用户
     * @param deptAlias 部门别名
     * @param userAlias 用户别名
     */
    public void dataScopeFilter(JoinPoint joinPoint, SysUserVO user, String deptAlias, String userAlias) {
        StringBuilder sqlString = new StringBuilder();
        for (SysRole role : user.getRoles()) {
            Integer dataScope = role.getDataScope();
            // 1.全部数据权限
            if (UserConstants.StateEnum.ROLE_DATA_SCOPE_ALL.getCode().equals(dataScope)) {
                sqlString = new StringBuilder();
                break;
            }
            // 2.自定数据权限
            // 类似 select d.* from sys_dept d where d.is_deleted = 0    or d.id in (select dept_id from sys_role_dept where role_id=?)
            if (UserConstants.StateEnum.ROLE_DATA_SCOPE_CUSTOM.getCode().equals(dataScope)) {
                sqlString.append(StringUtils.format(" or {}.id in ( select dept_id from sys_role_dept where role_id = {} )"
                        , deptAlias, role.getId()));
                log.info("DATA_SCOPE_CUSTOM:{}", sqlString.toString());
            }
            // 3.本部门数据权限
            // 类似 select d.* from sys_dept d where d.is_deleted = 0 or d.id = ?
            if (UserConstants.StateEnum.ROLE_DATA_SCOPE_DEPT.getCode().equals(dataScope)) {
                sqlString.append(StringUtils.format(" or {}.id = {}"
                        , deptAlias, user.getDeptId()));
                log.info("DATA_SCOPE_DEPT:{}", sqlString.toString());
            }
            // 4.本部门及以下数据权限
            // 类似 select d.* from sys_dept d where d.is_deleted = 0   or d.id in ( select id from sys_dept where id = ? or find_in_set( ? , ancestor_ids ))
            if (UserConstants.StateEnum.ROLE_DATA_SCOPE_DEPT_AND_CHILD.getCode().equals(dataScope)) {
                sqlString.append(StringUtils.format(" or {}.id in ( select id from sys_dept where id = {} or find_in_set( {} , ancestor_ids ) )"
                        , deptAlias, user.getDeptId(), user.getDeptId()));
                log.info("DATA_SCOPE_DEPT_AND_CHILD:{}", sqlString.toString());
            }
            // 5.仅本人数据权限
            // select u.* d.name as dept_name, d.leader from sys_user u
            //		left join sys_dept d on u.dept_id = d.dept_id
            //		where u.is_deleted = 0 or u.id = ?
            if (UserConstants.StateEnum.ROLE_DATA_SCOPE_SELF.getCode().equals(dataScope)) {
                if (StringUtils.isNotBlank(userAlias)) {
                    sqlString.append(StringUtils.format(" or {}.id = {}", userAlias, user.getId()));
                } else {
                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
                    sqlString.append(" or 1=0 ");
                }
                log.info("DATA_SCOPE_SELF:{}", sqlString.toString());
            }
        }
        if (StringUtils.isNotBlank(sqlString.toString())) {
            // 获取最后一个参数
            Object[] args = joinPoint.getArgs();
            Object params = args[args.length - 1];
            log.info("joinPoint.getArgs(): {}", Arrays.toString(joinPoint.getArgs()));
            log.info("params :{}", params);
            if (StringUtils.isNotNull(params) && params instanceof BaseDTO) {
                BaseDTO<?> baseDTO = (BaseDTO<?>) params;
                // 去掉 or 开始 如 " or {}.id = in ( select id from sys_dept where id = {} or find_in_set( {} , ancestor_ids)"
                // 变成 {}.id = in ( select id from sys_dept where id = {} or find_in_set( {} , ancestor_ids)  然后 and 拼接
                baseDTO.getParams().put(Constants.DATA_SCOPE, " and (" + sqlString.substring(4) + ")");
                log.info("sqlString:{}", sqlString.toString());
            }
        }

    }
}
